package com.keyue.common.utils;

import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.google.common.collect.Maps;
import com.keyue.common.constant.Constant;
import com.keyue.common.constant.ServerResult;
import com.keyue.common.constant.ServerResultCode;
import com.keyue.common.exception.BusinessException;
import com.keyue.domain.vo.CaptchaMessageVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;


@Slf4j
@Service
public class SmsUtils {


    @Value("${outsys.sms.regionId}")
    private String regionId;

    @Value("${outsys.sms.accessKeyId}")
    private String accessKeyId;

    @Value("${outsys.sms.secret}")
    private String secret;

    @Value("${outsys.sms.domain}")
    private String domain;

    @Value("${outsys.sms.version}")
    private String version;

    @Value("${outsys.sms.action}")
    private String action;

    @Value("${outsys.sms.signName}")
    private String signName;

    @Value("${outsys.sms.templateCode}")
    private String templateCode;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private ImgCaptchaUtils imgCaptchaUtils;

    /**
     * 短信验证码前缀 + 手机号码
     * 1分钟有效
     */
    private static String SMS_CODE_KEY_PRE = "SMS_CODE_%s";


    /**
     * 发送短信验证码
     *
     * @param captchaMessageVO
     * @return
     */
    public ServerResult sendCaptchaCode(CaptchaMessageVO captchaMessageVO) {
        String phone = captchaMessageVO.getPhone();

        imgCaptchaUtils.validateImgCaptcha(captchaMessageVO.getImgCaptchaCode(), captchaMessageVO.getImgCaptchaUuid());

        if (checkLimitMobileSendCount(phone)) {
            return ServerResult.fail(ServerResultCode.SMS_SEND_OVER_LIMIT_ERROR);
        }
        String captchaCode = getCaptchaCode(phone);
        ServerResult serverResult = send(buildSmsMessageVO(phone, captchaCode));
        if (serverResult.checkNotSuccess()) {
            return serverResult;
        }
        setSmsCaptchaCode(phone, captchaCode);
        return serverResult;
    }

    /**
     * 获取发送的短信验证码
     *
     * @param phone
     * @param captchaCode
     * @return
     */
    private void setSmsCaptchaCode(String phone, String captchaCode) {
        redisUtil.set(String.format(SMS_CODE_KEY_PRE, phone), captchaCode, 1L, TimeUnit.MINUTES);
    }

    /**
     * 获取发送的短信验证码
     *
     * @param phone
     * @return
     */
    private String getSmsCaptchaCode(String phone) {
        return redisUtil.get(String.format(SMS_CODE_KEY_PRE, phone));
    }

    /**
     * @param phone
     */
    private void deleteSmsCaptchaCode(String phone) {
        redisUtil.delete(String.format(SMS_CODE_KEY_PRE, phone));
    }

    /**
     * @param phone
     * @param smsCaptchaCode
     */
    public void validateSmsCaptcha(String phone, String smsCaptchaCode) {
        // 查询验证码
        String code = getSmsCaptchaCode(phone);
        // 清除验证码
        deleteSmsCaptchaCode(phone);
        if (StringUtils.isBlank(code)) {
            throw new BusinessException(ServerResultCode.SMS_CAPTCHA_ERROR);
        }
        if (StringUtils.isBlank(smsCaptchaCode) || !smsCaptchaCode.equalsIgnoreCase(code)) {
            throw new BusinessException(ServerResultCode.SMS_CAPTCHA_EXPIRE_ERROR);
        }
    }

    /**
     * @param phone
     * @param smsCaptchaCode
     */
    public boolean validateSmsCaptchaV2(String phone, String smsCaptchaCode) {
        // 查询验证码
        String code = getSmsCaptchaCode(phone);
        // 清除验证码
        deleteSmsCaptchaCode(phone);
        if (StringUtils.isBlank(code)) {
            return false;
        }
        if (StringUtils.isBlank(smsCaptchaCode) || !smsCaptchaCode.equalsIgnoreCase(code)) {
            return false;
        }
        return true;
    }

    /**
     * @param phone
     * @param captchaCode
     * @return
     */
    private CommonRequest buildSmsMessageVO(String phone, String captchaCode) {
        CommonRequest request = new CommonRequest();
        request.setMethod(MethodType.POST);
        request.setDomain(domain);
        request.setVersion(version);
        request.setAction(action);
        request.putQueryParameter("RegionId", regionId);
        StringBuilder builder = new StringBuilder();
        int index = 0;
        List<String> phoneNumbers = Arrays.asList(phone);
        for (String phoneNumber : phoneNumbers) {
            builder.append(phoneNumber + ((index++ < phoneNumbers.size() - 1) ? "," : ""));
        }
        request.putQueryParameter("PhoneNumbers", builder.toString());
        request.putQueryParameter("SignName", signName);
        request.putQueryParameter("TemplateCode", templateCode);
        Map<String, String> templateParam = Maps.newHashMap();
        templateParam.put("code", captchaCode);
        String templateParamJson = JSONObject.toJSONString(templateParam);
        request.putQueryParameter("TemplateParam", templateParamJson);
        log.info("开始发送短信,手机号 {},captchaCode:{}", phone, captchaCode);
        return request;
    }


    /**
     * 限制一分钟最多发送两次短信
     *
     * @param mobile
     * @return
     */
    private boolean checkLimitMobileSendCount(String mobile) {
        String dateTime = DateUtils.format(LocalDateTime.now(), DateUtils.DATE_TIME_WITHOUT_SECONDS);

        String key = "msg:" + mobile + Constant.COLON_CHARACTER + dateTime;

        Long count = redisUtil.incrBy(key, Constant.ONE);
        return Objects.nonNull(count) && count > Constant.TWO ? true : false;
    }

    /**
     * 生成验证码
     *
     * @param phone
     * @return
     */
    public String getCaptchaCode(String phone) {
        String src = phone + DateUtils.format(new Date(), DateUtils.YYMMDDHHMMSS);
        String code = Math.abs(src.hashCode()) + "";
        if (code.length() >= 4) {
            return code.substring(code.length() - 4, code.length());
        } else {
            StringBuilder buf = new StringBuilder(code);
            while (buf.length() < 4) {
                buf.insert(0, "0");
            }
            return buf.toString();
        }
    }


    /**
     * @param request
     * @return
     */
    public ServerResult send(CommonRequest request) {
        DefaultProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, secret);
        IAcsClient client = new DefaultAcsClient(profile);

        try {
            CommonResponse response = client.getCommonResponse(request);
            log.info("短信发送,结果 {}", response.getData());
        } catch (Exception e) {
            log.error("短信发送异常:", e);
            return ServerResult.fail("短信发送异常:" + e);
        }

        return ServerResult.success();
    }

}
